home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Programmer Disk
/
The Programmer Disk (Microforum).iso
/
xpro
/
c3
/
pro24
/
cmdline.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-08-06
|
11KB
|
342 lines
/* cmdline.c -- command line parsing routines */
/*
* This module is designed to allow various modules to scan (and rescan)
* the command line for applicable arguments. The goal is to hide as
* much information about switches and their names as possible so that
* switches become more consistent across applications and so that the
* author of an application need not do a lot of work to provide numerous
* options. Instead, each module scans the command line for its own
* arguments.
*
* Command lines are of the following form:
* command -s1 -s2 opt2 -s3 arg1 arg2 -s4 opt4 arg3
* Note that there are three kinds of command line parameters:
* (1) A Switch is a "-" followed by a name, e.g. "-s1"
* (2) An Option is a Switch followed by a space and name, e.g. "-s2 opt2"
* (3) An Argument is a name by itself, e.g. "arg1"
* Note also that a switch followed by an argument looks just like an
* option, so a list of valid option names is necessary to disambiguate.
*
* A main program that uses cmdline.c should do the following:
* (1) create an array of pointers to strings (char *names[]) that
* contains every possible option name
* (2) create another array of pointers to strings that contains
* every possible switch name
* (2) call cl_init(switches, nsw, options, nopt, argv, argc)
* cl_init will report an error (to stderr) if it finds any illegal
* switch or option names.
*
* Afterward, switches, options, and arguments can be accessed by
* calling cl_switch, cl_option, and cl_arg. If cl_switch or cl_option
* is called with a switch name that was not mentioned in the call to
* cl_init, an error will result. This indicates that the application
* author omitted a valid switch or option name when calling cl_init.
* This is an error because the full set of names is needed for error
* checking and to distinguish arguments from options.
*
* cl_nswitch and cl_noption are similar to cl_switch and cl_option,
* except they each take a list of equivalent switch or option names.
* This makes it simple to allow both verbose (-debug) and terse (-d) names.
*/
/*****************************************************************************
* Change Log
* Date | Change
*-----------+-----------------------------------------------------------------
* 13-Jun-86 | Created Change Log
* 6-Aug-86 | Modified for Lattice 3.0 -- use "void" to type some routines
*****************************************************************************/
#include "cext.h"
#include "stdio.h"
#include "cmdline.h"
private char **voptions; /* valid options */
private int noptions; /* number of options */
private char **vswitches; /* valid switches */
private int nswitches; /* number of switches */
private char **argv; /* command line argument vector */
private int argc; /* length of argv */
private int cl_rdy = false; /* set to true when initialized */
/*****************************************************************************
* Routines local to this module
*****************************************************************************/
private void check_names();
private int find_match();
private int find_string();
private void ready_check();
/****************************************************************
* check_names
* Inputs:
* char *names[]: array of alternative switch or option names
* int nnames: number of alternative switch or option names
* char *valid[]: array of valid names
* int nvalid: number of valid names
* Effect:
* Checks that all names are in validnames. If not, print
* an error message.
*****************************************************************/
private void check_names(names, nnames, valid, nvalid)
char *names[];
int nnames;
char *valid[];
int nvalid;
{
int i; /* loop counters */
for (i = 0; i < nnames; i++) {
if (find_string(names[i], valid, nvalid) >= nvalid) {
fprintf(stderr, "internal error detected by cmdline module:\n");
fprintf(stderr, "\t'%s' should be in valid lists\n", names[i]);
}
}
}
/****************************************************************
* cl_arg
* Inputs:
* n: the index of the arg needed
* Results:
* pointer to the nth arg, or NULL if none exists
* arg 0 is the command name
*****************************************************************/
char *cl_arg(n)
int n;
{
int i = 1;
if (n <= 0) return argv[0];
while (i < argc) {
if (*argv[i] == '-') {
if (find_string(argv[i], voptions, noptions) < noptions)
i += 2; /* skip name and option */
else i += 1; /* skip over switch name */
} else if (n == 1) {
return argv[i];
} else { /* skip over argument */
n--;
i++;
}
}
return NULL;
}
/*****************************************************************************
* cl_init
* Inputs:
* char *switches[]: array of switch names
* int nsw: number of switch names
* char *options[]: array of option names
* int nopt: number of option names
* char *av: array of command line fields (argv)
* int ac: number of command line fields (argc)
* Effect:
* Checks that all command line entries are valid.
* Saves info for use by other routines.
* Returns:
* True if syntax checks OK, otherwise false
*****************************************************************************/
boolean cl_init(switches, nsw, options, nopt, av, ac)
char *switches[];
int nsw;
char *options[];
int nopt;
char *av[];
int ac;
{
int i; /* index into argv */
boolean result = true;
vswitches = switches; nswitches = nsw;
voptions = options; noptions = nopt;
argv = av; argc = ac;
for (i = 1; i < argc; i++) { /* case fold lower */
int j;
for (j = 0; j < strlen(argv[i]); j++)
argv[i][j] = tolower(argv[i][j]);
}
/* check command line syntax: */
i = 1;
while (i < argc) {
if (*argv[i] == '-') {
if (find_string(argv[i], voptions, noptions) < noptions) {
i += 1; /* skip name and option */
if (i < argc && *argv[i] == '-') {
fprintf(stderr, "missing argument after %s\n", argv[i-1]);
result = false;
i += 1;
}
} else if (find_string(argv[i], vswitches, nswitches) <
nswitches) {
i += 1; /* skip over switch name */
} else {
fprintf(stderr, "invalid switch: %s\n", argv[i]);
i += 1;
result = false;
}
} else i++; /* skip over argument */
}
cl_rdy = true;
return result;
}
/****************************************************************
* cl_noption
* Inputs:
* char *names[]: array of alternative switch names
* int nnames: number of alternative switch names
* Result:
* returns pointer to if one exists, otherwise null
* Effect:
* looks for pattern in command line of the form "-n s",
* where n is a member of names. Returns pointer to s.
* Implementation:
* find the option name, then
* see if the switch is followed by a string that does
* not start with "-"
*****************************************************************/
char *cl_noption(names, nnames)
char *names[];
int nnames;
{
int i; /* index of switch */
ready_check();
check_names(names, nnames, voptions, noptions);
i = find_match(names, nnames) + 1; /* point at the option */
if (i < argc) { /* make sure option exists */
if (*(argv[i]) != '-') return argv[i];
}
return NULL;
}
/*****************************************************************
* cl_nswitch
* Inputs:
* char *names[]: array of alternative switch names
* int nnames: number of alternative switch names
* Effect:
* Checks that names is valid.
* Finds a pattern in command line of the form "-n", where
* n is a member of names.
* Result:
* returns pointer to command line switch if one exists,
* otherwise null
*****************************************************************/
char *cl_nswitch(names, nnames)
char *names[];
int nnames;
{
int i; /* index of switch */
ready_check();
check_names(names, nnames, vswitches, nswitches);
i = find_match(names, nnames);
if (i < argc) return argv[i];
/* else */ return NULL;
}
/****************************************************************
* cl_option
* Inputs:
* char *name: option name
* Outputs:
* returns char *: the option string if found, otherwise null
****************************************************************/
char *cl_option(name)
char *name;
{
char *names[1]; /* array to hold name */
names[0] = name;
return cl_noption(names, 1);
}
/****************************************************************
* cl_switch
* Inputs:
* char *name: switch name
* Outputs:
* boolean: true if switch found
****************************************************************/
boolean cl_switch(name)
char *name;
{
char *names[1]; /* array to hold name */
names[0] = name;
return cl_nswitch(names, 1) != NULL;
}
/****************************************************************
* find_match
* Inputs:
* char *names[]: array of alternative switch or option names
* int nnames: number of alternative switch or option names
* Effect:
* Looks for command line switch that matches one of names.
* Returns:
* Index of switch if found, argc if not found.
*****************************************************************/
private int find_match(names, nnames)
char *names[];
int nnames;
{
int j; /* loop counter */
for (j = 0; j < argc; j++) {
if (find_string(argv[j], names, nnames) < nnames) return j;
}
return argc;
}
/****************************************************************
* find_string
* Inputs:
* char *s: string to find
* char *names[]: array of strings
* int nnames: number of strings
* Effect:
* Looks for s in names
* Returns:
* Index of s in names if found, nnames if not found
*****************************************************************/
private int find_string(s, names, nnames)
char *s;
char *names[];
int nnames;
{
int i; /* loop counter */
for (i = 0; i < nnames; i++) {
if (strcmp(s, names[i]) == 0) {
return i;
}
}
return nnames;
}
/****************************************************************
* ready_check
* Effect:
* Halt program if cl_rdy is not true.
*****************************************************************/
private void ready_check()
{
if (!cl_rdy) {
fprintf(stderr,
"Internal error: cl_init was not called, see cmdline.c\n");
exit(1);
}
}